<template>
  <div class="ai-stream-demo">
    <div class="input-section">
      <textarea
          v-model="question"
          placeholder="请输入您的问题，例如：生成企业风险评估报告"
          rows="4"
          cols="50"
      ></textarea>
      <br />
      <button @click="askQuestion" :disabled="loading">提问</button>
      <button @click="generateEnterpriseRiskReport" :disabled="loading">生成企业风险评估报告</button>
      <button @click="generatePolicyMatchingReport" :disabled="loading">生成政策匹配报告</button>
      <button @click="clearContent">清空内容</button>
    </div>
    <div class="response-section">
      <div v-if="loading">⏳ 正在接收数据...</div>
      <!-- 使用 key 强制重新渲染，有时有助于解决更新问题 -->
      <div class="markdown-content" :key="displayContent" v-html="renderedContent"></div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { marked } from 'marked'
import DOMPurify from 'dompurify'

// --- 配置 marked ---
marked.setOptions({
  breaks: true,
  gfm: true,
  sanitize: false,
  smartLists: true,
  smartypants: false,
  headerIds: false,
  mangle: false,
});

// --- 状态变量 ---
const question = ref('')
// const lastFullContent = ref('') // 存储累积的原始 content 数据
const lastFullContent = ref('') // 存储上一次收到的完整文本
const displayContent = ref('')  // 用于打字机效果显示的内容
const loading = ref(false)
const typewriterQueue = ref([]) // 打字机队列
const isTyping = ref(false)     // 是否正在打字

// --- 计算属性：渲染 Markdown 为 HTML ---
const renderedContent = computed(() => {
  if (!displayContent.value) return ''

  try {
    let htmlContent = marked.parse(displayContent.value)
    htmlContent = DOMPurify.sanitize(htmlContent)
    return htmlContent
  } catch (error) {
    console.error('Markdown 解析错误:', error)
    return DOMPurify.sanitize(displayContent.value.replace(/\n/g, '<br>'))
  }
})

// --- 处理新内容 ---
const handleNewContent = (content) => {
  if (content) {
    lastFullContent.value += content
    typewriterEffect(content)
  }
}

// --- 打字机效果 ---
const typewriterEffect = async (newText) => {
  if (isTyping.value) {
    typewriterQueue.value.push(newText)
    return
  }

  isTyping.value = true
  const currentLength = displayContent.value.length
  const targetText = displayContent.value + newText

  for (let i = currentLength; i < targetText.length; i++) {
    displayContent.value = targetText.substring(0, i + 1)
    const delay = targetText[i] === '\n' ? 30 : 15
    await new Promise(resolve => setTimeout(resolve, delay))
  }

  isTyping.value = false

  if (typewriterQueue.value.length > 0) {
    const nextText = typewriterQueue.value.shift()
    await typewriterEffect(nextText)
  }
}

// --- 清空内容 ---
const clearContent = () => {
  lastFullContent.value = ''
  displayContent.value = ''
  question.value = ''
  typewriterQueue.value = []
  isTyping.value = false
}

// --- 通用 SSE 连接函数 (基于 fetch) ---
const connectSSE = (url, data) => {
  // 重置状态
  lastFullContent.value = ''
  displayContent.value = ''
  typewriterQueue.value = []
  isTyping.value = false
  loading.value = true

  // --- EventSource Polyfill (基于你提供的代码和 fetch) ---
  class EventSourcePolyfill {
    constructor(url, options = {}) {
      this.url = url
      this.method = options.method || 'GET'
      this.headers = options.headers || {}
      this.payload = options.payload || null
      this.onmessage = null
      this.onerror = null
      this.listeners = {}
      this.currentEventType = null
      this.connect()
    }

    connect() {
      fetch(this.url, {
        method: this.method,
        headers: this.headers,
        body: this.payload
      })
          .then(response => {
            const contentType = response.headers.get('content-type')
            if (!contentType || !contentType.includes('text/event-stream')) {
              throw new Error('响应不是SSE格式')
            }

            const reader = response.body.getReader()
            const decoder = new TextDecoder('utf-8')
            let buffer = ''

            const processStream = () => {
              reader.read().then(({ done, value }) => {
                if (done) {
                  // 流结束，触发完成事件
                  if (this.listeners['stream-complete']) {
                    this.listeners['stream-complete'].forEach(callback => callback({data: '[DONE]'}));
                  }
                  return
                }

                buffer += decoder.decode(value, { stream: true })
                // 根据 SSE 规范，使用 \n\n 分隔事件，但逐行处理更常见且兼容性好
                const lines = buffer.split(/\r\n|\n|\r/)
                buffer = lines.pop() // 保留不完整的行

                for (const line of lines) {
                  if (line.trim() === '') continue

                  if (line.startsWith('event:')) {
                    this.currentEventType = line.substring(6).trim()
                  } else if (line.startsWith('data:')) {
                    const dataStr = line.substring(5).trim()

                    // --- 处理 [DONE] 或特殊结束标记 ---
                    if (dataStr === '[DONE]') {
                      if (this.listeners['stream-complete']) {
                        this.listeners['stream-complete'].forEach(callback => callback({data: '[DONE]'}));
                      }
                      continue; // 跳过后续处理
                    }

                    // --- 解析 JSON 格式的 data ---
                    try {
                      const dataObj = JSON.parse(dataStr)

                      // ✅ 提取 content 字段（根据你的后端响应结构）
                      const content = dataObj.choices[0].delta.content || '';

                      const event = {
                        data: content,
                        type: this.currentEventType || 'message'
                      }

                      if (this.onmessage) {
                        this.onmessage(event)
                      }
                      if (this.listeners[event.type]) {
                        this.listeners[event.type].forEach(callback => callback(event))
                      }
                      this.currentEventType = null // 重置事件类型
                    } catch (e) {
                      console.warn('SSE 数据解析失败:', e, '原始数据:', dataStr)
                      // 如果不是 JSON，当作纯文本处理（向后兼容）
                      const event = {
                        data: dataStr,
                        type: this.currentEventType || 'message'
                      }
                      if (this.listeners[event.type]) {
                        this.listeners[event.type].forEach(callback => callback(event))
                      }
                    }
                  }
                }
                processStream()
              }).catch(error => {
                if (this.onerror) {
                  this.onerror(error)
                }
              })
            }
            processStream()
          })
          .catch(error => {
            if (this.onerror) {
              this.onerror(error)
            }
          })
    }

    addEventListener(type, callback) {
      if (!this.listeners[type]) {
        this.listeners[type] = []
      }
      this.listeners[type].push(callback)
    }

    close() {
      console.warn('EventSourcePolyfill: close() not fully implemented for fetch-based SSE.')
    }
  }

  // --- 创建 SSE 连接 ---
  const eventSource = new EventSourcePolyfill(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    payload: JSON.stringify(data)
  })

  // --- 监听通用消息（已移除，避免与特定事件重复处理）---
  // eventSource.onmessage = (event) => {
  //   // 此处已注释，因为后端发送的是带有event类型的SSE数据
  //   // 会被下面的addEventListener处理，避免重复
  // }

  // --- 监听特定事件 ---
  eventSource.addEventListener('ai-answer', (event) => {
    // event.data 已经是从 choices[0].delta.content 提取的内容
    handleNewContent(event.data)
  })

  // --- 监听特定事件（如 enterprise-risk-report）---
  eventSource.addEventListener('enterprise-risk-report', (event) => {
    // event.data 已经是从 choices[0].delta.content 提取的内容
    handleNewContent(event.data)
  })

  eventSource.addEventListener('policy-matching-report', (event) => {
    // event.data 已经是从 choices[0].delta.content 提取的内容
    handleNewContent(event.data)
  })

  eventSource.addEventListener('stream-complete', (event) => {
    typewriterEffect('\n\n✅ 报告生成完成')
    eventSource.close()
    loading.value = false
  })

  eventSource.addEventListener('stream-error', (event) => {
    typewriterEffect('\n\n❌ ' + (event.data || '发生未知错误'))
    eventSource.close()
    loading.value = false
  })

  // --- 错误处理 ---
  eventSource.onerror = (error) => {
    console.error('SSE连接错误:', error)
    typewriterEffect('\n\n❌ 连接发生错误: ' + error.message)
    eventSource.close()
    loading.value = false
  }

  return eventSource
}

// --- 提问 ---
const askQuestion = () => {
  if (!question.value.trim()) {
    alert('请输入问题')
    return
  }
  const data = {
    question: question.value,
    snCode: '9150011720364325XN' // 示例 SN
  }
  connectSSE('/api/ai/questions', data)
}

// --- 生成企业风险评估报告 ---
const generateEnterpriseRiskReport = () => {
  const data = {
    question: question.value || '请生成企业风险评估报告', // 提供默认问题
    snCode: '9150011720364325XN'
  }
  connectSSE('/api/ai/enterprise-risk-report', data)
}

// --- 生成政策匹配报告 ---
const generatePolicyMatchingReport = () => {
  const data = {
    question: question.value || '请生成政策匹配报告', // 提供默认问题
    snCode: '9150011720364325XN'
  }
  connectSSE('/api/ai/policy-matching-report', data)
}
</script>

<style scoped>
.ai-stream-demo {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  text-align: left;
}

.input-section {
  margin-bottom: 30px;
}

.input-section textarea {
  width: 100%;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 6px;
  resize: vertical;
  font-size: 16px;
}

.input-section button {
  margin-top: 15px;
  margin-right: 10px;
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 16px;
  transition: background-color 0.2s;
}

.input-section button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.input-section button:hover:not(:disabled) {
  background-color: #0056b3;
}

.response-section {
  border: 1px solid #e1e4e8;
  border-radius: 6px;
  padding: 20px;
  background-color: #fafbfc;
  min-height: 300px;
  box-shadow: inset 0 1px 2px rgba(27, 31, 35, 0.075);
  overflow-y: auto; /* 如果内容过多，允许滚动 */
}

/* 确保 markdown-content 内的元素能正常显示 */
.markdown-content {
  line-height: 1.6;
  color: #24292e;
  word-wrap: break-word; /* 长单词换行 */
}

.markdown-content h1,
.markdown-content h2,
.markdown-content h3 {
  margin-top: 1.5em;
  margin-bottom: 1em;
  font-weight: 600;
  line-height: 1.25;
}

.markdown-content h1 {
  font-size: 2em;
  padding-bottom: 0.3em;
  border-bottom: 1px solid #eaecef;
}

.markdown-content h2 {
  font-size: 1.5em;
  padding-bottom: 0.3em;
  border-bottom: 1px solid #eaecef;
}

.markdown-content p {
  margin-top: 0;
  margin-bottom: 1em;
}

.markdown-content ul,
.markdown-content ol {
  padding-left: 2em;
  margin-top: 0;
  margin-bottom: 1em;
}

.markdown-content li {
  margin-bottom: 0.25em;
}

.markdown-content pre {
  padding: 16px;
  overflow: auto;
  font-size: 85%;
  line-height: 1.45;
  background-color: #f6f8fa;
  border-radius: 6px;
  margin-top: 0;
  margin-bottom: 16px;
}

.markdown-content code {
  padding: 0.2em 0.4em;
  margin: 0;
  font-size: 85%;
  background-color: rgba(27, 31, 35, 0.05);
  border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
}
</style>